package com.hengyu.oauth2.core;

import com.hengyu.oauth2.jpa.HengYuClientDetailJPA;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
import org.springframework.security.oauth2.provider.*;
import org.springframework.stereotype.Service;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * 自定义oauth2查询终端token业务逻辑
 * 项目名称：OAuth2Example
 * 项目版本：V1.0
 * 包名称：com.example.oauth
 * 创建人：yuqy
 * 创建时间：2017/3/16 15:34
 * 修改人：yuqy
 * 修改时间：2017/3/16 15:34
 * 修改备注：
 */
@Service
public class HengYuOAuth2ClientDetailsService implements ClientDetailsService,ClientRegistrationService {

    //注入查询终端详情SpringDataJpa数据接口
    @Autowired
    private HengYuClientDetailJPA clientDetailDAO;

    private PasswordEncoder passwordEncoder;

    private HengYuOAuth2ClientDetailsService.JsonMapper mapper = createJsonMapper();

    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }
    //日志对象
    private static final Log logger = LogFactory.getLog(HengYuOAuth2ClientDetailsService.class);

    /**
     * 根据clientId查询出终端详细信息
     * @param clientId 中
     * @return
     * @throws InvalidClientException
     */
    public ClientDetails loadClientByClientId(String clientId) throws InvalidClientException {
        logger.info("clientId : "+clientId);
        try {
            ClientDetails details = (ClientDetails) clientDetailDAO.findOne(clientId);
            return details;
        } catch (EmptyResultDataAccessException var4) {
            throw new NoSuchClientException("No client with requested id: " + clientId);
        }
    }

    public void addClientDetails(ClientDetails clientDetails) throws ClientAlreadyExistsException {
        try {
            Object[] fields = getFields(clientDetails);
            for (int i =0;i<fields.length;i++)
            {
                System.out.println(fields[i]);
            }
        } catch (DuplicateKeyException var3) {
            throw new ClientAlreadyExistsException("Client already exists: " + clientDetails.getClientId(), var3);
        }
    }

    @Override
    public void updateClientDetails(ClientDetails clientDetails) throws NoSuchClientException {

    }

    @Override
    public void updateClientSecret(String s, String s1) throws NoSuchClientException {

    }

    @Override
    public void removeClientDetails(String s) throws NoSuchClientException {

    }

    @Override
    public List<ClientDetails> listClientDetails() {
        return null;
    }

    private Object[] getFields(ClientDetails clientDetails) {
        Object[] fieldsForUpdate = this.getFieldsForUpdate(clientDetails);
        Object[] fields = new Object[fieldsForUpdate.length + 1];
        System.arraycopy(fieldsForUpdate, 0, fields, 1, fieldsForUpdate.length);
        fields[0] = clientDetails.getClientSecret() != null?this.passwordEncoder.encode(clientDetails.getClientSecret()):null;
        return fields;
    }
    private Object[] getFieldsForUpdate(ClientDetails clientDetails) {
        String json = null;

        try {
            json = this.mapper.write(clientDetails.getAdditionalInformation());
        } catch (Exception var4) {
            logger.warn("Could not serialize additional information: " + clientDetails, var4);
        }

        return new Object[]{clientDetails.getResourceIds() != null? StringUtils.collectionToCommaDelimitedString(clientDetails.getResourceIds()):null, clientDetails.getScope() != null?StringUtils.collectionToCommaDelimitedString(clientDetails.getScope()):null, clientDetails.getAuthorizedGrantTypes() != null?StringUtils.collectionToCommaDelimitedString(clientDetails.getAuthorizedGrantTypes()):null, clientDetails.getRegisteredRedirectUri() != null?StringUtils.collectionToCommaDelimitedString(clientDetails.getRegisteredRedirectUri()):null, clientDetails.getAuthorities() != null?StringUtils.collectionToCommaDelimitedString(clientDetails.getAuthorities()):null, clientDetails.getAccessTokenValiditySeconds(), clientDetails.getRefreshTokenValiditySeconds(), json, this.getAutoApproveScopes(clientDetails), clientDetails.getClientId()};
    }
    private String getAutoApproveScopes(ClientDetails clientDetails) {
        if(clientDetails.isAutoApprove("true")) {
            return "true";
        } else {
            Set<String> scopes = new HashSet();
            Iterator var3 = clientDetails.getScope().iterator();

            while(var3.hasNext()) {
                String scope = (String)var3.next();
                if(clientDetails.isAutoApprove(scope)) {
                    scopes.add(scope);
                }
            }

            return StringUtils.collectionToCommaDelimitedString(scopes);
        }
    }
    private static class Jackson2Mapper implements HengYuOAuth2ClientDetailsService.JsonMapper {
        private ObjectMapper mapper;

        private Jackson2Mapper() {
            this.mapper = new ObjectMapper();
        }

        public String write(Object input) throws Exception {
            return this.mapper.writeValueAsString(input);
        }

        public <T> T read(String input, Class<T> type) throws Exception {
            return this.mapper.readValue(input, type);
        }
    }
    private static class JacksonMapper implements HengYuOAuth2ClientDetailsService.JsonMapper {
        private org.codehaus.jackson.map.ObjectMapper mapper;

        private JacksonMapper() {
            this.mapper = new org.codehaus.jackson.map.ObjectMapper();
        }

        public String write(Object input) throws Exception {
            return this.mapper.writeValueAsString(input);
        }

        public <T> T read(String input, Class<T> type) throws Exception {
            return this.mapper.readValue(input, type);
        }
    }
    private static class NotSupportedJsonMapper implements HengYuOAuth2ClientDetailsService.JsonMapper {
        private NotSupportedJsonMapper() {
        }

        public String write(Object input) throws Exception {
            throw new UnsupportedOperationException("Neither Jackson 1 nor 2 is available so JSON conversion cannot be done");
        }

        public <T> T read(String input, Class<T> type) throws Exception {
            throw new UnsupportedOperationException("Neither Jackson 1 nor 2 is available so JSON conversion cannot be done");
        }
    }


    interface JsonMapper {
        String write(Object var1) throws Exception;

        <T> T read(String var1, Class<T> var2) throws Exception;
    }

    private static HengYuOAuth2ClientDetailsService.JsonMapper createJsonMapper() {
        return (HengYuOAuth2ClientDetailsService.JsonMapper)
                (ClassUtils.isPresent("org.codehaus.jackson.map.ObjectMapper", (ClassLoader)null) ?
                        new HengYuOAuth2ClientDetailsService.JacksonMapper() :
                        (ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", (ClassLoader)null) ?
                                new HengYuOAuth2ClientDetailsService.Jackson2Mapper():new HengYuOAuth2ClientDetailsService.NotSupportedJsonMapper()));
    }
}
